package jwt

import (
	"time"

	"github.com/golang-jwt/jwt/v4"
	"github.com/pkg/errors"
)

// CustomClaims 自定义声明类型 并内嵌jwt.RegisteredClaims
// jwt包自带的jwt.RegisteredClaims只包含了官方字段
// 假设我们这里需要额外记录一个username字段，所以要自定义结构体
// 如果想要保存更多信息，都可以添加到这个结构体中
type CustomClaims struct {
	// 可根据需要自行添加字段
	UserID               int64  `json:"user_id"`
	Username             string `json:"username"`
	jwt.RegisteredClaims        // 内嵌标准的声明
}

const (
	accessTokenExpireDuration = time.Minute * 10000
	// refreshTokenExpireDuration = time.Hour * 24
)

// CustomSecret 用于加盐的字符串
var CustomSecret = []byte("富强、民主、文明、和谐；自由、平等、公正、法治；爱国、敬业、诚信、友善")

// GenToken 生成JWT
func GenToken(userID int64, username string) (string, error) {
	// 创建一个我们自己的声明
	claims := CustomClaims{
		userID,
		username, // 自定义字段
		jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(accessTokenExpireDuration)),
			Issuer:    "bluebell", // 签发人
		},
	}
	// 使用指定的签名方法创建签名对象
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	// 使用指定的secret签名并获得完整的编码后的字符串token
	return token.SignedString(CustomSecret)
}

// ParseToken 解析JWT
func ParseToken(tokenString string) (*CustomClaims, error) {
	// 解析token
	// 如果是自定义Claim结构体则需要使用 ParseWithClaims 方法
	token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, keyFunc)
	if err != nil {
		return nil, err
	}
	// 对token对象中的Claim进行类型断言
	if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid { // 校验token
		return claims, nil
	}
	return nil, errors.New("invalid token")
}

// RefreshToken 通过rToken刷新aTokens, 前端在aToken失效的时候，重新发起请求，并且带上rToken和aToken
// func RefreshToken(aToken, rToken string) (newAToken, newRToken string, err error) {
// 	// refresh Token 无效直接返回
// 	if _, err = jwt.Parse(rToken, keyFunc); err != nil {
// 		return
// 	}
//
// 	// 从旧access token中解析出claims数据
// 	var claims CustomClaims
// 	_, err = jwt.ParseWithClaims(aToken, &claims, keyFunc)
// 	v, _ := err.(*jwt.ValidationError)
//
// 	// 当access token是过期错误，并且refresh token没有过期就创建一个新的access token
// 	if v.Errors == jwt.ValidationErrorExpired {
// 		return GenToken(claims.UserID, claims.Username)
// 	}
// 	return
// }

func keyFunc(*jwt.Token) (i interface{}, err error) { return CustomSecret, nil }
